package ckw.network;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import ckw.database.Configuration;
import ckw.database.DatabaseManager;
import ckw.database.Election;
import ckw.database.OKW;
import ckw.gui.MainWindowC;

import core.messages.Dane;
import core.messages.Info;
import core.messages.TestMsg;
import core.messages.IMessage;
import core.modules.database.corebase.ElectionData;

/**
 * 
 * @author Maks
 * Odpowiada za  komunikacje
 * 
 */

public class ConnectionC {
	ServerSocket SSocket = null;
	ArrayList<Komisja> komisje = new ArrayList<Komisja>();
	Queue queue = null;
	Queue2 k2 = null;
	Thread sender = null;
	StanC stanC = null;
	Thread nasluchuj = null;
	DatabaseManager db = null;
	
	public ArrayList<Komisja> getKomisje() {
		return komisje;
	}

	public void setKomisje(ArrayList<Komisja> komisje) {
		this.komisje = komisje;
	}
	
	public void start(StanC stanC, DatabaseManager db){
		//tworzymy kolejke wiadomosc i watek wysylajacy startujemy
		queue = new Queue();
		k2 = new Queue2();
		this.stanC = stanC;
		sender = new Thread(new Sender(queue, k2));
		sender.start();
		this.db = db;
		
		aktualizacjaKomisji(); // TODO: raczej do usunięcia
		
	}
	
	public void aktualizacjaKomisji(){
		ArrayList<OKW> okws = (ArrayList<OKW>) db.getAll(OKW.class);
		for(Komisja k: komisje){
			if(k.getSocket()!=null)
				try {
					k.getSocket().close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		komisje.clear();
		
		for (OKW o : okws){
			Komisja k;
			if (o.getConfiguration() != null) {
				Configuration config = db.get(Configuration.class, o.getConfiguration().getId());
			//	System.out.println("* "+config.getIp());
				k = new Komisja(null, null, null, null, o.getIdentificationField(), config.getIp() , o.getName());
		
			} else
			{
				k = new Komisja(null, null, null, null, o.getIdentificationField(), "0" , o.getName());
			}
			komisje.add(k);
		}
	}
	
	// tworzy socket serera centrali na podanym adresie
	public void startServer(int port, InetAddress adres) throws IOException{
		if(SSocket == null){
			SSocket = new ServerSocket(port, 999, adres);
			
			// ustawiamy wlaczenie
			System.out.println("Serwer centrali wystartowal!");
			stanC.setWlaczony(true);
			
		}

	}
	
	//tworzy watek nasluchujacy na komisje, bedzie trzeba ulepszyc, zeby jakos ten watek przechowywala, ackeptowala;
	public void listen(){
		 nasluchuj = new Thread(new Listen(this, SSocket, k2, stanC));
		 nasluchuj.start();
	}
	
	// wysyla wiadomosc w dol
	public void sendDown(Komisja k, IMessage o) throws Exception{
		System.out.println("Centrala wysyla do komisji nr:msg: " + o.getNumber() + " : " + o.getType());
		if(k.getOos()==null)
			throw new Exception("Nie udalo sie wyslac wiadomosci do komisji" + k.getName() );
		QueueItem tmp = new QueueItem(o, k);
		queue.put(tmp);
	}
	
	// rozpoczyna glosowanie, wysyla do wszystkich wiadomosc o tym, nieuzywane
	public void startGlosowania(){
		for(int i = 0; i<komisje.size(); i++){
			Info info = new Info(stanC.getNr(),1);
			try {
				sendDown(komisje.get(i), info);
			} catch (Exception e) {
				e.printStackTrace();
				e.getMessage();
			}
		}
	//	stanC.setGlosRozpoczete(true);
	//	stanC.setGlosZakonczone(false);
		MainWindowC.rozpoczetoGlosowanie();
	}
	
	//w dol do wszystkich NIE UZYWAC POZA TESTAMI 
	public void sendDownToAll(IMessage o){
		for(int i = 0; i<komisje.size(); i++){
			try {
				sendDown(komisje.get(i), o);
				//o.setNumber(stanC.getNr());
			} catch (Exception e) {
				e.printStackTrace();
				e.getMessage();
			}
		}
	}
	
	// rozpoczyna glosowanie, wysyla do wszystkich wiadomosc o tym
	public void wyslijDaneToAll(){
		List<Election> elections = db.getAll(Election.class);
		for (Election election : elections) {
			Map<String, ElectionData> mapa = db.getElectionDataToSend(election);
			for(Komisja komisja : komisje){
				ElectionData electionData = mapa.get(komisja.getId());
				Dane msg = new Dane(stanC.getNr(), electionData);
				OKW okw = db.getOKW(komisja.getId());

				if (okw != null) {
					db.setIsSend(election, okw, false);
					MainWindowC.aktualizujWybory();					
					try {
						sendDown(komisja, msg);
					} catch (Exception e) {
						e.printStackTrace();
						e.getMessage();
					}
				}				
			}
		}
	}
	
	public void wyslijDane(Komisja k, String token){
		if (token == null)
			return;
		
		Election election = db.getElectionByToken(token, k.getId());
		if (election == null)
			return;

		OKW okw = db.getOKW(k.getId());
		ElectionData electionData = db.getElectionDataToSend(election, okw); 
		if (electionData == null)
			return;
		Dane msg = new Dane(stanC.getNr(), electionData);
		if (okw != null){
			db.setIsSend(election, okw, false);
			MainWindowC.aktualizujWybory();			
			try {
				sendDown(k, msg);
			} catch (Exception e) {
				e.printStackTrace();
				e.getMessage();
			}
		}
	}
	
	// wysyla informacje o koncu glosowania, nieuzywane
	public void endVote(){
		for(int i = 0; i<komisje.size(); i++){
			Info info = new Info(stanC.getNr(),2);
			try {
				sendDown(komisje.get(i), info);
			} catch (Exception e) {
				e.printStackTrace();
				e.getMessage();
			}
		}
	//	stanC.setGlosZakonczone(true);
	//	stanC.setGlosRozpoczete(false);
		MainWindowC.zakonczonoGlosowanie();
	}

	public void stop() {
		if(sender!=null)
			sender.stop();
		try {
			if(SSocket != null)
				SSocket.close();
			for(Komisja k: komisje){
				if(k.getOis()!=null)
					k.getOis().close();
				if(k.getOos()!=null)
					k.getOos().close();
				if(k.getSocket()!=null)
					k.getSocket().close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	public Komisja getKomisja(String data) {
		for(Komisja k: komisje){
			if(k.getId().equals(data))
				return k;
		}
		return null;
	}

	// do testow
	public int testuj() {
		for(Komisja k: komisje){
			Info info = new Info(stanC.getNr(),3);
			try {
				sendDown(k, info);
			} catch (Exception e) {
				e.printStackTrace();
				e.getMessage();
			}
		}
		return komisje.size();
	}

	public ArrayList<Komisja> getKomisjeOprocz(ArrayList<TestMsg> oprocz) {
		ArrayList<Komisja> wynik = new ArrayList<Komisja>();
		for(Komisja k: komisje){
			boolean jest = false;
			for(TestMsg t: oprocz){
				if(t.getOkw().equals(k.getId()))
					jest = true;
			}
			if(!jest)
				wynik.add(k);
		}
		return wynik;
	}
	
}
